#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <errno.h> // 定义了全局错误码 errno
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/sysmacros.h>

char type(mode_t mode){
    if(S_ISREG(mode))return '-';
    if(S_ISCHR(mode))return 'c';
    if(S_ISDIR(mode))return 'd';
    if(S_ISBLK(mode))return 'b';
    if(S_ISFIFO(mode))return 'f';
    if(S_ISLNK(mode))return 'l';
    if(S_ISSOCK(mode))return 's';
}

char *permission(mode_t mode){
    static char buf[10];
    char pm[] = {'r', 'w', 'x'};
    for(int i = 0; i < 9; i++)
        buf[i] = mode & (0400>>i) ? pm[i % 3] : '-';
    return buf;
}

//如果是文件
void show_file(const char *file_name){
    struct stat st;
    bzero(&st, sizeof(st));
    stat(file_name, &st);
    printf("%c", type(st.st_mode));
    printf("%s ", permission(st.st_mode));
    printf("%ld ", st.st_nlink);
    printf("%s %s ", getpwuid(st.st_uid)->pw_name, getgrgid(st.st_gid)->gr_name);
    if(S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
        printf("%u, %u ", major(st.st_rdev), minor(st.st_rdev));
    else
        printf("%ld ", st.st_size);
    char file_time[24];
    strncpy(file_time, ctime(&st.st_atime), 24);
    printf("%s ", file_time);
    printf("%s\n", file_name);
}

void show_dir(const char *file_name){
    DIR *dp = opendir(file_name);
    chdir(file_name);
    struct dirent *ep = NULL;
    while (1){
        ep = readdir(dp);
        if(ep == NULL)break;
        if(ep->d_name[0] == '.')continue;
        show_file(ep->d_name);
    }
    closedir(dp);
}

int main(int argc, char const *argv[])
{
    if(argc != 2){
        printf("参数数量错误!\n");
        return 0;
    }
    struct stat st;
    bzero(&st, sizeof(st));
    stat(argv[1], &st);
    if(!S_ISDIR(st.st_mode))
        show_file(argv[1]);
    else if(S_ISDIR(st.st_mode))
        show_dir(argv[1]);
    else printf("未知文件\n");
    return 0;
}
